package com.starview.star.operators.arrays.runtime;

import java.util.ArrayList;
import java.util.List;

import com.starview.platform.data.EvaluationException;
import com.starview.platform.data.IArray;
import com.starview.platform.data.IFunction;
import com.starview.platform.data.IPattern;
import com.starview.platform.data.IValue;
import com.starview.platform.data.type.IType;
import com.starview.platform.data.type.Refresher;
import com.starview.platform.data.type.StandardTypes;
import com.starview.platform.data.type.TypeUtils;
import com.starview.platform.data.type.TypeVar;
import com.starview.platform.data.value.Array;
import com.starview.platform.data.value.Factory;
import com.starview.star.operators.CafeEnter;
import com.starview.star.operators.relation.runtime.ValueSort;

public class ArrayUpdate
{

  public static class ArraySetElement implements IFunction
  {
    public static final String name = "__array_set_element";

    @CafeEnter
    public static IArray enter(IArray array, int index, IValue el) throws EvaluationException
    {
      return array.substituteCell(index, el);
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return enter((IArray) args[0], Factory.intValue(args[1]), args[2]);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      TypeVar v = new TypeVar();
      IType arrayType = TypeUtils.arrayType(v);
      return Refresher.generalize(TypeUtils.functionType(arrayType, StandardTypes.rawIntegerType, v, arrayType));
    }
  }

  public static class UpdateIntoArray implements IFunction
  {
    public static final String name = "__update_into_array";

    @CafeEnter
    public static IArray enter(Array array, IPattern filter, IFunction transform) throws EvaluationException
    {
      return array.updateUsingPattern(filter, transform);
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return enter((Array) args[0], (IPattern) args[1], (IFunction) args[2]);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      TypeVar tv = new TypeVar();
      IType arrayType = TypeUtils.arrayType(tv);
      IType ptnType = TypeUtils.patternType(TypeUtils.tupleType(), tv);
      IType funType = TypeUtils.functionType(tv, tv);
      return Refresher.generalize(TypeUtils.functionType(arrayType, ptnType, funType, arrayType));
    }
  }

  public static class ArrayDelete implements IFunction
  {
    public static final String name = "__delete_from_array";

    @CafeEnter
    public static IArray enter(Array array, IPattern filter) throws EvaluationException
    {
      return array.deleteUsingPattern(filter);
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return enter((Array) args[0], (IPattern) args[1]);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      TypeVar tv = new TypeVar();
      IType aryType = TypeUtils.arrayType(tv);
      return Refresher.generalize(TypeUtils.functionType(aryType, TypeUtils.patternType(TypeUtils.tupleType(), tv),
          aryType));
    }
  }

  public static class ArraySort implements IFunction
  {
    public static final String name = "__array_sort";

    @CafeEnter
    public static Array enter(Array src, IFunction comparator) throws EvaluationException
    {
      List<IValue> tmp = new ArrayList<IValue>(src.size());
      for (IValue el : src)
        tmp.add(el);

      List<IValue> sorted = ValueSort.quickSort(tmp, comparator);
      return Array.newArray(sorted);
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return enter((Array) args[0], (IFunction) args[1]);
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      IType v = new TypeVar();
      IType comparatorType = TypeUtils.functionType(v, v, StandardTypes.booleanType);
      IType colType = TypeUtils.arrayType(v);
      return Refresher.generalize(TypeUtils.functionType(colType, comparatorType, colType));
    }
  }
}
